package bl.tools;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;

import ml.options.OptionSet;
import ml.options.Options;

public class MethodRunner {
	
	private static final int maxPartSize = 25;
	
	private static String cr, dir;
	
	ArrayList<String> classes;
	
	private static int noClasses = -1, offset = 0;
	
	private ArrayList<String> partitionList = new ArrayList<String>();
	
	MethodRunner(ArrayList<String> partitionList){
		if(partitionList.size() == 0){ // default classes to split
			this.partitionList.add("org.mozilla.javascript.Parser");
			this.partitionList.add("org.mozilla.javascript.optimizer.Codegen");
		} else
			this.partitionList = partitionList;
	}
	
	/**
	 * @param args
	 * @throws IOException 
	 * @throws InterruptedException 
	 */
	public static void main(String[] args) throws IOException, InterruptedException {
		Options opt = new Options(args);
		opt.addSet("foo", 0, 10).addOption("cr", 
				Options.Separator.BLANK, Options.Multiplicity.ZERO_OR_ONE).addOption("noClasses",
				Options.Separator.EQUALS, Options.Multiplicity.ZERO_OR_ONE).addOption("dir",
				Options.Separator.BLANK, Options.Multiplicity.ZERO_OR_ONE).addOption("offset",
				Options.Separator.EQUALS, Options.Multiplicity.ZERO_OR_ONE).addOption("makeLists", Options.Multiplicity.ZERO_OR_ONE);
		
		OptionSet set = opt.getMatchingSet(false, false);
		
		if (set == null) {
			System.out.println("Usage:\n---------------------\n" +
					"\t-cr \t ClassRanking a CSV as from Lists2CSV\n"+
					"\t-dir \t working directory\n"+
					"\t-noClasses= \t k, top k classes of -cr will be analyzed\n" +
					"\t-offset= \t start at this line in the csv\n" +
					"[Class1, ..., ClassN] Classes that have to be splitted");
			System.out.println("\nThe options library says:\n" + opt.getCheckErrors());
			System.exit(1);
		}
		if(set.isSet("cr"))
			cr = set.getOption("cr").getResultValue(0);
		if(set.isSet("noClasses"))
			noClasses = Integer.parseInt(set.getOption("noClasses").getResultValue(0));

		if(set.isSet("dir"))
			dir = set.getOption("dir").getResultValue(0);
		
		if(set.isSet("offset"))
			offset = Integer.parseInt(set.getOption("offset").getResultValue(0));
		
		MethodRunner mr = new MethodRunner(set.getData());
		if(set.isSet("makeLists"))
			mr.writeLists(dir, noClasses);
		else
			mr.exec();
	}
	
	void writeLists(String dir, int noClasses) throws IOException{
		makeLists(dir);
		ArrayList<String> topK = topKList(cr, noClasses);
		makeListsTopK(dir, topK);
	}
	
	void exec() throws IOException, InterruptedException{
		System.out.println("Read in class ranking...");
		if(offset != 0)
			classes = listAll(cr, offset);
		else
			classes = listAll(cr);
		System.out.println("Run the ranking...");
		runRanking(classes, dir);
		System.out.println("Writing output...");
		makeLists(dir);
		ArrayList<String> topK = topKList(cr, noClasses);
		makeListsTopK(dir, topK);
	}
	
	ArrayList<String> topKList(String csv, int noClasses) throws IOException{
		ArrayList<String> out = new ArrayList<String>();
		FileReader fr = new FileReader(csv);
		BufferedReader br = new BufferedReader(fr);
		String line;
		int i = 0;
		while( (line = br.readLine()) != null ){
			if(i >= noClasses)
				break;
			out.add(line.split(";")[1]);
			i++;
		}
		return out;
	}
	
	ArrayList<String> listAll(String csv) throws IOException{
		return listAll(csv, 0);
	}
	
	ArrayList<String> listAll(String csv, int offset) throws IOException{
		ArrayList<String> out = new ArrayList<String>();
		FileReader fr = new FileReader(csv);
		BufferedReader br = new BufferedReader(fr);
		String line;
		int i = 0;
		while( (line = br.readLine()) != null ){
			if(i >= offset-1)
				out.add(line.split(";")[1]);
			i++;
		}
		return out;
	}
	
	void runRanking(ArrayList<String> classes, String dir) throws IOException, InterruptedException{
		int i = offset;
		for( String c : classes ){
			try{
				String cmd = "--mine " +
				  "-method " + 
				  "-i " + dir + "\\data" + " " +
				  "-reincludeJre " +
				  "-closeGraph " +
				  "-wof=_0 ";
				if( ! partitionList.contains(c)){
					cmd += "-suffix=_" + i + " " + c;
					bl.Main.main(cmd.split("\\s"));
				} else {
					String list = "\\list_methods_" + i;
					LOCCParser lp = new LOCCParser(dir + "\\size.txt");
					lp.writeMethods(dir + list, c, maxPartSize);
					for(int j = 0; j < lp.getNoPartitions(); j++){
						String cmd_x = cmd;
						cmd_x += "-suffix=_" + i + "-" + j + " -list=" + list + "_" + j + ".lst" + " " + c ;
						bl.Main.main(cmd_x.split("\\s"));
					}
				}
				i++;
			} catch(java.lang.NullPointerException e) {
				continue;
			}
			
		}
	}
	
	//TODO make a list for top-k
	void makeLists(String dir) throws IOException{
		File[] files = new File(dir).listFiles();
		String cmd = "-o ranking_method_all.csv " +
		  			 "-folder " + dir + " " +
		  			 "-i size.txt ";
		for(File f : files){
			if(f.getCanonicalPath().matches(".*method.*Scoring.*")){
				cmd += f.getName() + " ";
			}
		}
		Lists2CSV.main(cmd.split("\\s"));
	}
	
	private void makeListsTopK(String dir, ArrayList<String> topK) throws IOException {
		File[] files = new File(dir).listFiles();
		String cmd = "-o ranking_method_topK.csv " +
		  			 "-folder " + dir + " " +
		  			 "-i size.txt ";
		for(File f : files){
			if(f.getCanonicalPath().matches(".*method.*Scoring.*")){
				if(isInList(f, topK))
					cmd += f.getName() + " ";
			}
		}
		Lists2CSV.main(cmd.split("\\s"));
	}
	
	private boolean isInList(File f, ArrayList<String> list) throws IOException{
		FileReader fr = new FileReader(f);
		BufferedReader br = new BufferedReader(fr);
		String line;
		while( (line = br.readLine()) != null ){
			for(String currentClass : list){
				if(line.matches("USED OPTIONS.*"+currentClass+".*"))
					return true;
			}
		}
		return false;		
	}


}
